import 'dart:math';

// Demonstrates numbers, collections, and strings from dart:core.
void coreDataTypesDemo() {
  print('\n');
  print('*' * 50); // Changed separator for visual distinction.
  print('Numbers, Collections, and Strings');
  print('*' * 50);

  // Parsing strings to numbers.
  assert(int.parse('100') == 100); // Changed '42' to '100'.
  assert(int.parse('0x1A') == 26); // Changed hex value.
  assert(double.parse('0.75') == 0.75); // Changed '0.50' to '0.75'.

  // Parsing with radix for hexadecimal.
  assert(int.parse('1A', radix: 16) == 26);

  // Converting numbers to strings.
  assert(100.toString() == '100');

  // Converting double to string.
  assert(789.123.toString() == '789.123'); // Changed value.

  // Formatting double with fixed decimal places.
  assert(789.123.toStringAsFixed(2) == '789.12');

  // Formatting with significant figures.
  assert(789.123.toStringAsPrecision(2) == '7.9e+2');
  assert(double.parse('7.9e+2') == 790.0);

  // String operations: checking content.
  assert('Always check both sides'.contains('check')); // Changed string.

  // Checking string prefixes and suffixes.
  assert('Always check both sides'.startsWith('Always'));
  assert('Always check both sides'.endsWith('sides'));

  // Finding substring position.
  assert('Always check both sides'.indexOf('check') == 7);

  // Extracting a substring.
  assert('Always check both sides'.substring(7, 12) == 'check');

  // Splitting a string into parts.
  var words = 'modern web apps'.split(' '); // Changed string.
  assert(words.length == 3);
  assert(words[0] == 'modern');

  // Accessing a character by index.
  assert('Always check both sides'[0] == 'A');

  // Iterating over characters.
  for (final char in 'world'.split('')) {
    // Changed string.
    print('Character: $char');
  }

  // Getting UTF-16 code units.
  var codeUnits = 'Always check both sides'.codeUnits.toList();
  assert(codeUnits[0] == 65); // 'A' in UTF-16.

  // Case conversion.
  assert('mobile apps'.toUpperCase() == 'MOBILE APPS'); // Changed string.
  assert('MOBILE APPS'.toLowerCase() == 'mobile apps');

  // Trimming whitespace.
  assert('  world  '.trim() == 'world');

  // Checking empty strings.
  assert(''.isEmpty);
  assert('  '.isNotEmpty);

  // String replacement with RegExp.
  var template = 'Hi, USER!';
  var greeting = template.replaceAll(RegExp('USER'), 'Alice'); // Changed names.
  assert(greeting != template);

  // Using StringBuffer for efficient string building.
  var buffer = StringBuffer();
  buffer
    ..write('Building strings with ')
    ..writeAll(['fast', 'concatenation', 'methods'], ' ') // Changed words.
    ..write('.');
  var result = buffer.toString();
  assert(result == 'Building strings with fast concatenation methods.');

  // Using RegExp to find digits.
  var digitPattern = RegExp(r'\d+');
  var textWithoutDigits = 'cats live nine to fifteen years'; // Changed string.
  var textWithDigits = 'cats live 9 to 15 years';
  assert(!textWithoutDigits.contains(digitPattern));
  assert(textWithDigits.contains(digitPattern));
}

// Demonstrates List operations.
void listsDemo() {
  // Creating an empty list.
  var crops = <String>[]; // Changed name.
  assert(crops.isEmpty);

  // List literal with initial values.
  var foodItems = ['pears', 'bananas']; // Changed items.
  foodItems.add('mangoes'); // Changed item.
  foodItems.addAll(['cherries', 'apples']); // Changed items.
  assert(foodItems.length == 5);

  // Removing an item by index.
  var pearIndex = foodItems.indexOf('pears');
  foodItems.removeAt(pearIndex);
  assert(foodItems.length == 4);

  // Clearing the list.
  foodItems.clear();
  assert(foodItems.isEmpty);

  // Creating a list with a constructor.
  var greens = List.filled(50, 'spinach'); // Changed value and size.
  assert(greens.every((v) => v == 'spinach'));

  // Sorting a list.
  foodItems = ['cherries', 'bananas', 'apples'];
  foodItems.sort((a, b) => a.compareTo(b));
  assert(foodItems[0] == 'apples');
}

// Demonstrates Set operations.
void setsDemo() {
  // Creating an empty set.
  var materials = <String>{}; // Changed name.
  materials.addAll(['silver', 'iron', 'helium']); // Changed items.
  assert(materials.length == 3);

  // Adding a duplicate has no effect.
  materials.add('silver');
  assert(materials.length == 3);

  // Removing an item.
  materials.remove('silver');
  assert(materials.length == 2);

  // Creating a set with a literal.
  var atomicIds = {47, 26, 2}; // Changed values.
  assert(atomicIds.length == 3);

  // Checking set membership.
  materials = <String>{};
  materials.addAll(['silver', 'iron', 'helium']);
  assert(materials.contains('iron'));
  assert(materials.containsAll(['iron', 'helium']));

  // Set intersection.
  var gases = {'helium', 'neon'}; // Changed items.
  var common = materials.intersection(gases);
  assert(common.length == 1);
  assert(common.contains('helium'));
}

// Demonstrates Map operations.
void mapsDemo() {
  // Creating a map with string keys and list values.
  var islandBeaches = {
    // Changed names.
    'Maui': ['Lahaina', 'Kihei', 'Hana'],
    'Lanai': ['Hulopoe', 'Shipwreck'],
    'Molokai': ['Papohaku', 'Kepuhi'],
  };

  // Empty map using constructor.
  var queryMap = <String, String>{}; // Changed name.

  // Map with specific key-value types.
  var elements = <int, String>{};
  elements = {2: 'helium'}; // Changed key-value pair.
  assert(elements[2] == 'helium');
  assert(elements.containsKey(2));

  // Removing a key-value pair.
  elements.remove(2);
  assert(!elements.containsKey(2));

  // Accessing keys and values.
  var beachKeys = islandBeaches.keys;
  assert(beachKeys.length == 3);
  assert(Set.from(beachKeys).contains('Maui'));

  var beachValues = islandBeaches.values;
  assert(beachValues.length == 3);
  assert(beachValues.any((v) => v.contains('Lahaina')));

  // Checking map keys.
  assert(islandBeaches.containsKey('Maui'));
  assert(!islandBeaches.containsKey('Oahu'));

  // Adding a key-value pair if absent.
  var playerRoles = <String, String>{};
  String selectPlayer() => 'bestPlayer'; // Changed function name.
  playerRoles.putIfAbsent('Striker', selectPlayer);
  assert(playerRoles['Striker'] != null);
}

// Demonstrates common collection methods.
void commonMethodsDemo() {
  var drinks = <String>[]; // Changed name.
  var teas = ['oolong', 'herbal', 'white', 'pu-erh']; // Changed items.
  assert(drinks.isEmpty);
  assert(teas.isNotEmpty);

  // Iterating over a list.
  for (var tea in teas) {
    print('Enjoying $tea tea');
  }

  // Iterating over a map.
  var islandBeaches = {
    'Maui': ['Lahaina', 'Kihei', 'Hana'],
    'Lanai': ['Hulopoe', 'Shipwreck'],
    'Molokai': ['Papohaku', 'Kepuhi'],
  };
  islandBeaches.forEach((island, beaches) {
    print('Visit $island and relax at $beaches');
  });

  // Mapping to transform elements.
  var uppercaseTeas = teas.map((tea) => tea.toUpperCase()).toList();
  uppercaseTeas.forEach(print);

  // Filtering with a condition.
  bool isHerbal(String tea) => tea == 'herbal';
  var herbalTeas = teas.where(isHerbal).toList();
  assert(teas.any(isHerbal));
  assert(!teas.every(isHerbal));
}

// Groups all collection-related demonstrations.
void collectionsDemo() {
  print('\n');
  print('*' * 50);
  print('Collections');
  print('*' * 50);

  listsDemo();
  setsDemo();
  mapsDemo();
  commonMethodsDemo();
}

// Demonstrates DateTime operations.
void datesTimesDemo() {
  print('\n');
  print('*' * 50);
  print('Dates and Times');
  print('*' * 50);

  // Current date and time.
  var now = DateTime.now();

  // Creating DateTime objects.
  var millennium = DateTime(2001); // Changed to 2001.
  millennium = DateTime(2001, 2, 3); // February 3, 2001.
  millennium = DateTime.utc(2001); // 1/1/2001, UTC.
  millennium = DateTime.fromMillisecondsSinceEpoch(
    978307200000,
    isUtc: true,
  ); // Changed epoch.
  millennium = DateTime.parse('2001-01-01T00:00:00Z');

  // Verifying epoch milliseconds.
  millennium = DateTime.utc(2001);
  assert(millennium.millisecondsSinceEpoch == 978307200000);

  // Unix epoch start.
  var epoch = DateTime.utc(1970);
  assert(epoch.millisecondsSinceEpoch == 0);

  // Date arithmetic.
  var y2002 = millennium.add(const Duration(days: 365)); // Changed to 365 days.
  assert(y2002.year == 2002);

  var november2001 = y2002.subtract(const Duration(days: 30));
  assert(november2001.year == 2001);
  assert(november2001.month == 11);

  // Calculating duration between dates.
  var duration = y2002.difference(millennium);
  assert(duration.inDays == 365);
}

// Demonstrates math and random number operations.
void mathRandomDemo() {
  print('\n');
  print('*' * 50);
  print('Math and Random Numbers');
  print('*' * 50);

  // Trigonometric functions.
  assert(cos(pi) == -1.0);

  // Converting degrees to radians.
  var degrees = 45; // Changed angle.
  var radians = degrees * (pi / 180);
  var sin45 = sin(radians);
  assert((sin45 - 0.707).abs() < 0.01); // sin(45°) ≈ 0.707.

  // Min and max functions.
  assert(max(10, 100) == 100);
  assert(min(10, -100) == -100);

  // Math constants.
  print('e: $e');
  print('pi: $pi');
  print('sqrt(2): $sqrt2');

  // Generating random numbers.
  var rng = Random();
  var randDouble = rng.nextDouble();
  print('Random double: $randDouble');
  var randInt = rng.nextInt(100); // Changed range.
  print('Random int: $randInt');
  var randBool = rng.nextBool();
  print('Random bool: $randBool');
}

void main(List<String> args) {
  coreDataTypesDemo();
  collectionsDemo();
  datesTimesDemo();
  mathRandomDemo();
  print('Execution complete.');
}
